package criptografia;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.security.MessageDigest;

import javax.crypto.Cipher;
/**
 * Esse objeto criptografa e descriptografa dados baseado na chave armazenada no arquivo X1.
 * Tambem pode ser utilizado para geracao e comparacao de MD5 (assimetrica).
 * @author Equipe Localisa (Usa quem precisa!)
 */
public class Encriptador implements Serializable{
	
	private transient static final long serialVersionUID = 1L;
	private Chave chave;//Um objeto chave que sera persistido
	private transient ObjectOutputStream saida;
	private transient OutputStream arquivoSaida;
	private transient ObjectInputStream entrada;
	private transient InputStream arquivoEntrada;
	private transient Cipher cipher; 
	
        /**
         * @return se o arquivo X1 que contem a chave existe
         */
	private boolean verificaChaveExiste(){
		File arquivo = new File("arquivos/X1.ser");
		return arquivo.exists();
		
	}

	public Encriptador(){
		if(!this.verificaChaveExiste()){
			try{
				this.chave = new Chave();
				arquivoSaida = new FileOutputStream("arquivos/X1.ser");
				saida = new ObjectOutputStream(arquivoSaida);
				saida.writeObject(chave);
			}catch(Exception e){
				System.out.println("Erro na gravacao da chave");
			}
		}
		else{
			try{
				arquivoEntrada = new FileInputStream("arquivos/X1.ser");
				entrada = new ObjectInputStream(arquivoEntrada);
				chave = (Chave) entrada.readObject();//Ler o objeto chave e faz um downcast
			}catch(Exception e){
				System.out.println("Erro na leitura da chave");
			}
		}
		try{
			cipher = Cipher.getInstance("AES");
		}catch(Exception e){
			System.out.println("Erro com o algoritimo");
		}
	}
	
	/**
	 * Criptografa um dado gerando um array de bytes com o dado criptografado
	 * @param O dado a ser criptografado
	 * @return Um array de bytes a ser gravado na persistencia
	 * @throws Exception Se o dado for nulo
	 */
	public byte[] encriptar(String dado) throws Exception{
		if(dado != null){
			cipher.init(Cipher.ENCRYPT_MODE, chave.getKey());
			return cipher.doFinal(dado.getBytes());
		}
		
		throw new Exception("A string nao pode ser nula");
	}
	
	/**
	 * Criptografa um dado gerando um array de bytes com o dado criptografado
	 * @param O dado a ser criptografado
	 * @return Um array de bytes a ser gravado na persistencia
	 * @throws Exception Se o dado for nulo
	 */
	public byte[] encriptar(int dado) throws Exception{
		cipher.init(Cipher.ENCRYPT_MODE, chave.getKey());
		return cipher.doFinal(Integer.toString(dado).getBytes());
	}
	
	/**
	 * Criptografa um dado e gera um array de bytes com o dado criptografado
	 * @param dado O dado criptografado
	 * @return Um array de bytes a ser gravado na persistencia
	 * @throws Exception Se ocorrerem problemas na geracao da cipher
	 */
	public byte[] encriptar(double dado) throws Exception{
		cipher.init(Cipher.ENCRYPT_MODE, chave.getKey());
		return cipher.doFinal(Double.toString(dado).getBytes());
	}
	
	/**
	 * Descriptografa dados
	 * @param dado O array de bytes
	 * @return String  O dado descriptografado
	 * @throws Exception Se ocorrerem problemas na geracao da cipher
	 */
	public String decriptar(byte[] dado) throws Exception{
		cipher.init(Cipher.DECRYPT_MODE, chave.getKey());
		byte[] decipherText = cipher.doFinal(dado);
		String retorno = "";
		for(int i=0; i< decipherText.length; i++){
			retorno = retorno + String.valueOf(((char) decipherText[i]));
		}
		return retorno;
	}
	
	/**
	 * Gera um hash da String passada como parametro.
         * Usado na comparacao e no armazenanamento de senhas.
	 * @param O dado cujo codigo hash sera criado
	 * @return O hash do dado passado
	 * @throws Exception Se ocorrerem problemas com o digest
	 */
	public String geraHashParaSenha(String dado) throws Exception{
		MessageDigest digest = MessageDigest.getInstance("SHA-512");
		digest.update(dado.getBytes());
		String retorno="";
		byte[] arrayHash = digest.digest();
		for(int i=0; i < arrayHash.length; i++){
			retorno = retorno+((char) arrayHash[i]);
		}
		return retorno;
	}
}